package com.zdw.zfw.admin.config;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.Filter;

import com.zdw.zfw.admin.core.jwt.JwtFilter;
import com.zdw.zfw.admin.core.jwt.JwtRealm;
import com.zdw.zfw.admin.core.jwt.StatelessDefaultSubjectFactory;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.DependsOn;

/**
 * Shiro 配置
 *
 * @author zdw
 * @date Sep 1, 2018
 */
@Configuration
public class ShiroConfig {
	
    @Bean
	public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
		shiroFilter.setSecurityManager(securityManager);
		// 自定义 OAuth2Filter 过滤器，替代默认的过滤器
		Map<String, Filter> filters = new HashMap<>(16);
		filters.put("jwtFilter", new JwtFilter());
		shiroFilter.setFilters(filters);
		// 访问路径拦截配置，"anon"表示无需验证，未登录也可访问
		Map<String, String> filterMap = new LinkedHashMap<>();
		filterMap.put("/webjars/**", "anon");
		// 查看SQL监控（druid）
		filterMap.put("/druid/**", "anon");
		// 首页和登录页面
		filterMap.put("/", "anon");
		filterMap.put("/login", "anon"); 
		// swagger
		filterMap.put("/swagger-ui.html", "anon");
        filterMap.put("/swagger-resources", "anon");
        filterMap.put("/v2/api-docs", "anon");
        filterMap.put("/webjars/springfox-swagger-ui/**", "anon");
        // 验证码
        filterMap.put("/captcha.jpg**", "anon");
        // 其他所有路径交给OAuth2Filter处理
		filterMap.put("/**", "jwtFilter");
		shiroFilter.setFilterChainDefinitionMap(filterMap);
		return shiroFilter;
	}

	/**
	 * 会话管理类 禁用session
	 * @return DefaultSessionManager
	 */
	@Bean
	public DefaultSessionManager defaultSessionManager() {
		DefaultWebSessionManager manager = new DefaultWebSessionManager();
		manager.setSessionIdUrlRewritingEnabled(false);
		manager.setSessionValidationSchedulerEnabled(false);
		return manager;
	}
    @Bean
    public Realm getShiroRealm(){
        return new JwtRealm();
    }

    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        // 注入 Realm 实现类，实现自己的登录逻辑
        securityManager.setRealm(getShiroRealm());

        // 关闭shiro自带的session
		securityManager.setSubjectFactory(new StatelessDefaultSubjectFactory());
		DefaultSubjectDAO defaultSubjectDAO = (DefaultSubjectDAO)securityManager.getSubjectDAO();
		DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = (DefaultSessionStorageEvaluator)defaultSubjectDAO.getSessionStorageEvaluator();
		defaultSessionStorageEvaluator.setSessionStorageEnabled(false);

		// 关闭shiro自带的session
		securityManager.setSessionManager(defaultSessionManager());
        return securityManager;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
    	return new LifecycleBeanPostProcessor();
	}

	/**
	 *  开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
	 * 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能
	 */
	@Bean
	@DependsOn({"lifecycleBeanPostProcessor"})
	public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
		DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
		advisorAutoProxyCreator.setProxyTargetClass(true);
		return advisorAutoProxyCreator;
	}

	/**
	 * 开启aop注解支持
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}
}